#include <Copyright.h>

/*******************************************************************************
* gtPIRL.c
*
* DESCRIPTION:
*       API definitions for PIRL Resources
*
* DEPENDENCIES:
*
* FILE REVISION NUMBER:
*******************************************************************************/

#include <msApi.h>
#include <gtSem.h>
#include <gtHwCntl.h>
#include <gtDrvSwRegs.h>

/****************************************************************************/
/* STATS operation function declaration.                                    */
/****************************************************************************/
static GT_STATUS pirlOperationPerform
(
    IN   GT_QD_DEV            *dev,
    IN   GT_PIRL_OPERATION    pirlOp,
    INOUT GT_PIRL_OP_DATA     *opData
);

static GT_STATUS pirlInitialize
(
    IN  GT_QD_DEV              *dev
);

static GT_STATUS pirlInitIRLUnit
(
    IN  GT_QD_DEV              *dev,
    IN    GT_U32                irlUnit
);

static GT_STATUS pirlDataToResource
(
    IN  GT_QD_DEV              *dev,
    IN  GT_PIRL_DATA        *pirlData,
    OUT GT_PIRL_RESOURCE    *res
);

static GT_STATUS pirlResourceToData
(
    IN  GT_QD_DEV              *dev,
    IN  GT_PIRL_RESOURCE    *res,
    OUT GT_PIRL_DATA        *pirlData
);

static GT_STATUS pirlWriteResource
(
    IN  GT_QD_DEV              *dev,
    IN    GT_U32                irlUnit,
    IN  GT_PIRL_RESOURCE    *res
);

static GT_STATUS pirlReadResource
(
    IN  GT_QD_DEV              *dev,
    IN    GT_U32                irlUnit,
    OUT GT_PIRL_RESOURCE    *res
);

static GT_STATUS pirlSetPortVec
(
    IN  GT_QD_DEV    *dev,
    IN  GT_U32        irlUnit,
    IN  GT_U32        portVec
);

static GT_STATUS pirlGetPortVec
(
    IN  GT_QD_DEV    *dev,
    IN  GT_U32        irlUnit,
    OUT GT_U32        *portVec
);

static GT_STATUS pirlSetFcMode
(
    IN  GT_QD_DEV    *dev,
    IN  GT_LPORT    port,
    IN  GT_PIRL_FC_DEASSERT        mode
);

/*******************************************************************************
* gpirlActivate
*
* DESCRIPTION:
*       This routine activates Ingress Rate Limiting for the given ports by
*        initializing a resource bucket, assigning ports, and configuring
*        Bucket Parameters.
*
* INPUTS:
*        irlUnit  - bucket to be used (0 ~ 11).
*       portVec  - the list of ports that share the bucket.
*        pirlData - PIRL resource parameters.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*        GT_BAD_PARAM - if invalid parameter is given
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None
*
*******************************************************************************/
GT_STATUS gpirlActivate
(
    IN  GT_QD_DEV     *dev,
    IN  GT_U32        irlUnit,
    IN  GT_U32        portVec,
    IN  GT_PIRL_DATA    *pirlData
)
{
    GT_STATUS           retVal;
    GT_PORT_STP_STATE    pState[MAX_SWITCH_PORTS];
    GT_LPORT            port;
    GT_PIRL_OPERATION    op;
    GT_PIRL_OP_DATA        opData;
    GT_PIRL_RESOURCE    pirlRes;

    DBG_INFO(("gpirlActivate Called.\n"));
    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_PIRL_RESOURCE))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* check if the given bucket number is valid */
    if (!GT_IS_IRLUNIT_VALID(dev,irlUnit))
    {
        DBG_INFO(("GT_BAD_PARAM irlUnit\n"));
        return GT_BAD_PARAM;
    }

    /* check if the given portVec is valid */
    if ((!portVec) || (portVec >= (GT_U32)(1<<dev->numOfPorts)))
    {
        DBG_INFO(("GT_BAD_PARAM portVec\n"));
        return GT_BAD_PARAM;
    }

    /* set or reset port's ingress resource bit based on the portVec */
    retVal = pirlSetPortVec(dev, irlUnit, portVec);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Getting Port State failed\n"));
        return retVal;
    }

    /* Disable ports that share the bucket */
    for(port=0; port<dev->numOfPorts; port++)
    {
        if(!GT_IS_PORT_SET(portVec,port))
            continue;

        retVal = gstpGetPortState(dev, port, &pState[port]);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Getting Port State failed\n"));
            return retVal;
        }

        retVal = gstpSetPortState(dev, port, GT_PORT_DISABLE);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Getting Port State failed\n"));
            return retVal;
        }
    }

    /* Program Tuning register */
    op = PIRL_WRITE_RESOURCE;
    opData.irlUnit = irlUnit;
    opData.irlReg = 0xF;
    opData.irlData = 0x7;
    retVal = pirlOperationPerform(dev,op,&opData);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed (statsOperationPerform returned GT_FAIL).\n"));
        return retVal;
    }

    /* Program the Ingress Rate Resource Parameters */
    retVal = pirlDataToResource(dev,pirlData,&pirlRes);
    if(retVal != GT_OK)
    {
        DBG_INFO(("PIRL Data to PIRL Resource conversion failed.\n"));
        return retVal;
    }

    retVal = pirlWriteResource(dev,irlUnit,&pirlRes);
    if(retVal != GT_OK)
    {
        DBG_INFO(("PIRL Write Resource failed.\n"));
        return retVal;
    }

    /* Initialize internal counters */
    retVal = pirlInitIRLUnit(dev,irlUnit);
    if(retVal != GT_OK)
    {
        DBG_INFO(("PIRL Write Resource failed.\n"));
        return retVal;
    }

    /* Program PirlFCMode for each port that shares Bucket */
    if (pirlRes.ebsLimitAction == ESB_LIMIT_ACTION_FC)
    {
        for(port=0; port<dev->numOfPorts; port++)
        {
            if(!GT_IS_PORT_SET(portVec,port))
                continue;

            retVal = pirlSetFcMode(dev,port,pirlData->fcDeassertMode[port]);
            if(retVal != GT_OK)
            {
                DBG_INFO(("PIRL FC Mode set failed.\n"));
                return retVal;
            }
        }
    }

    /* Set the ports in their original state */
    for(port=0; port<dev->numOfPorts; port++)
    {
        if(!GT_IS_PORT_SET(portVec,port))
            continue;

        retVal = gstpSetPortState(dev, port, pState[port]);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Getting Port State failed\n"));
            return retVal;
        }
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;

}


/*******************************************************************************
* gpirlDeactivate
*
* DESCRIPTION:
*       This routine deactivates Ingress Rate Limiting for the given bucket.
*        It simply removes every ports from the Ingress Rate Resource.
*        It is assumed that gpirlActivate has been successfully called with
*        the irlUnit before this function is called.
*
* INPUTS:
*        irlUnit  - bucket to be used (0 ~ 11).
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*        GT_BAD_PARAM - if invalid parameter is given
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None
*
*******************************************************************************/
GT_STATUS gpirlDeactivate
(
    IN  GT_QD_DEV     *dev,
    IN  GT_U32        irlUnit
)
{
    GT_STATUS           retVal;

    DBG_INFO(("gpirlDectivate Called.\n"));

    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_PIRL_RESOURCE))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* check if the given bucket number is valid */
    if (!GT_IS_IRLUNIT_VALID(dev,irlUnit))
    {
        DBG_INFO(("GT_BAD_PARAM\n"));
        return GT_BAD_PARAM;
    }

    /* reset port's ingress resource bit */
    retVal = pirlSetPortVec(dev, irlUnit, 0);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Getting Port State failed\n"));
        return retVal;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;
}


/*******************************************************************************
* gpirlUpdateParam
*
* DESCRIPTION:
*       This routine updates IRL Parameter.
*        It is assumed that gpirlActivate has been successfully called with
*        the given irlUnit before this function is called.
*
* INPUTS:
*        irlUnit  - bucket to be used (0 ~ 11).
*        pirlData - PIRL resource parameters.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*        GT_BAD_PARAM - if invalid parameter is given
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None
*
*******************************************************************************/
GT_STATUS gpirlUpdateParam
(
    IN  GT_QD_DEV     *dev,
    IN  GT_U32        irlUnit,
    IN  GT_PIRL_DATA    *pirlData
)
{
    GT_STATUS           retVal;
    GT_PORT_STP_STATE    pState[MAX_SWITCH_PORTS];
    GT_LPORT            port;
    GT_PIRL_RESOURCE    pirlRes;
    GT_U32                portVec;

    DBG_INFO(("gpirlUpdateParam Called.\n"));

    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_PIRL_RESOURCE))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* check if the given bucket number is valid */
    if (!GT_IS_IRLUNIT_VALID(dev,irlUnit))
    {
        DBG_INFO(("GT_BAD_PARAM\n"));
        return GT_BAD_PARAM;
    }

    /* get port list that share ingress resource */
    retVal = pirlGetPortVec(dev, irlUnit, &portVec);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Getting Port State failed\n"));
        return retVal;
    }

    /* check if the given portVec is valid */
    if (!portVec)
    {
        DBG_INFO(("IRL Unit not Activated\n"));
        return GT_FAIL;
    }

    /* Disable ports that share the bucket */
    for(port=0; port<dev->numOfPorts; port++)
    {
        if(!GT_IS_PORT_SET(portVec,port))
            continue;

        retVal = gstpGetPortState(dev, port, &pState[port]);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Getting Port State failed\n"));
            return retVal;
        }

        retVal = gstpSetPortState(dev, port, GT_PORT_DISABLE);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Getting Port State failed\n"));
            return retVal;
        }
    }

    /* Program the Ingress Rate Resource Parameters */
    retVal = pirlDataToResource(dev,pirlData,&pirlRes);
    if(retVal != GT_OK)
    {
        DBG_INFO(("PIRL Data to PIRL Resource conversion failed.\n"));
        return retVal;
    }

    retVal = pirlWriteResource(dev,irlUnit,&pirlRes);
    if(retVal != GT_OK)
    {
        DBG_INFO(("PIRL Write Resource failed.\n"));
        return retVal;
    }

    /* Initialize internal counrters for the bucket */
    retVal = pirlInitIRLUnit(dev,irlUnit);
    if(retVal != GT_OK)
    {
        DBG_INFO(("PIRL Write Resource failed.\n"));
        return retVal;
    }

    /* Program PirlFCMode for each port that shares Bucket */
    if (pirlRes.ebsLimitAction == ESB_LIMIT_ACTION_FC)
    {
        for(port=0; port<dev->numOfPorts; port++)
        {
            if(!GT_IS_PORT_SET(portVec,port))
                continue;

            retVal = pirlSetFcMode(dev,port,pirlData->fcDeassertMode[port]);
            if(retVal != GT_OK)
            {
                DBG_INFO(("PIRL FC Mode set failed.\n"));
                return retVal;
            }
        }
    }

    /* Set the ports in their original state */
    for(port=0; port<dev->numOfPorts; port++)
    {
        if(!GT_IS_PORT_SET(portVec,port))
            continue;

        retVal = gstpSetPortState(dev, port, pState[port]);
        if(retVal != GT_OK)
        {
            DBG_INFO(("Getting Port State failed\n"));
            return retVal;
        }
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;

}


/*******************************************************************************
* gpirlReadParam
*
* DESCRIPTION:
*       This routine retrieves IRL Parameter.
*        It is assumed that gpirlActivate has been successfully called with
*        the given irlUnit before this function is called.
*
* INPUTS:
*        irlUnit  - bucket to be used (0 ~ 11).
*
* OUTPUTS:
*        pirlData - PIRL resource parameters.
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*        GT_BAD_PARAM - if invalid parameter is given
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None
*
*******************************************************************************/
GT_STATUS gpirlReadParam
(
    IN  GT_QD_DEV     *dev,
    IN  GT_U32        irlUnit,
    OUT GT_PIRL_DATA    *pirlData
)
{
    GT_STATUS           retVal;
    GT_LPORT            port;
    GT_PIRL_RESOURCE    pirlRes;
    GT_U32                portVec;

    DBG_INFO(("gpirlReadParam Called.\n"));

    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_PIRL_RESOURCE))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* check if the given bucket number is valid */
    if (!GT_IS_IRLUNIT_VALID(dev,irlUnit))
    {
        DBG_INFO(("GT_BAD_PARAM\n"));
        return GT_BAD_PARAM;
    }

    /* get port list that share ingress resource */
    retVal = pirlGetPortVec(dev, irlUnit, &portVec);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Getting Port State failed\n"));
        return retVal;
    }

    /* check if the given portVec is valid */
    if (!portVec)
    {
        DBG_INFO(("IRL Unit not Activated\n"));
        return GT_FAIL;
    }

    /* Read the Ingress Rate Resource Parameters */
    retVal = pirlReadResource(dev,irlUnit,&pirlRes);
    if(retVal != GT_OK)
    {
        DBG_INFO(("PIRL Read Resource failed.\n"));
        return retVal;
    }

    retVal = pirlResourceToData(dev,&pirlRes,pirlData);
    if(retVal != GT_OK)
    {
        DBG_INFO(("PIRL Resource to PIRL Data conversion failed.\n"));
        return retVal;
    }

    /* Program PirlFCMode for each port that shares Bucket */
    if (pirlRes.ebsLimitAction == ESB_LIMIT_ACTION_FC)
    {
        for(port=0; port<dev->numOfPorts; port++)
        {
            if(!GT_IS_PORT_SET(portVec,port))
                continue;

            retVal = grcGetPirlFcMode(dev,port,&pirlData->fcDeassertMode[port]);
            if(retVal != GT_OK)
            {
                DBG_INFO(("PIRL FC Mode get failed.\n"));
                return retVal;
            }
        }
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;

}



/*******************************************************************************
* gpirlUpdatePortVec
*
* DESCRIPTION:
*       This routine updates port list that share the bucket.
*        It is assumed that gpirlActivate has been successfully called with
*        the given irlUnit before this function is called.
*
* INPUTS:
*        irlUnit  - bucket to be used (0 ~ 11).
*       portVec  - the list of ports that share the bucket.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*        GT_BAD_PARAM - if invalid parameter is given
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None
*
*******************************************************************************/
GT_STATUS gpirlUpdatePortVec
(
    IN  GT_QD_DEV     *dev,
    IN  GT_U32        irlUnit,
    IN  GT_U32        portVec
)
{
    GT_STATUS       retVal;
    GT_U32            tmpVec;

    DBG_INFO(("gpirlActivate Called.\n"));

    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_PIRL_RESOURCE))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* check if the given bucket number is valid */
    if (!GT_IS_IRLUNIT_VALID(dev,irlUnit))
    {
        DBG_INFO(("GT_BAD_PARAM\n"));
        return GT_BAD_PARAM;
    }

    /* check if the given portVec is valid */
    if ((!portVec) || (portVec > (GT_U32)(1<<dev->numOfPorts)))
    {
        DBG_INFO(("GT_BAD_PARAM\n"));
        return GT_BAD_PARAM;
    }

    /* get port list that share ingress resource */
    retVal = pirlGetPortVec(dev, irlUnit, &tmpVec);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Getting Port State failed\n"));
        return retVal;
    }

    /* check if the given portVec is valid */
    if (!tmpVec)
    {
        DBG_INFO(("IRL Unit not Activated\n"));
        return GT_FAIL;
    }

    /* set or reset port's ingress resource bit based on the portVec */
    retVal = pirlSetPortVec(dev, irlUnit, portVec);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Getting Port State failed\n"));
        return retVal;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;

}


/*******************************************************************************
* gpirlReadPortVec
*
* DESCRIPTION:
*       This routine retrieves port list that share the bucket.
*        It is assumed that gpirlActivate has been successfully called with
*        the given irlUnit before this function is called.
*
* INPUTS:
*        irlUnit  - bucket to be used (0 ~ 11).
*
* OUTPUTS:
*       portVec  - the list of ports that share the bucket.
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*        GT_BAD_PARAM - if invalid parameter is given
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*       None
*
*******************************************************************************/
GT_STATUS gpirlReadPortVec
(
    IN  GT_QD_DEV     *dev,
    IN  GT_U32        irlUnit,
    OUT GT_U32        *portVec
)
{
    GT_STATUS       retVal;

    DBG_INFO(("gpirlReadPortVec Called.\n"));

    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_PIRL_RESOURCE))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* check if the given bucket number is valid */
    if (!GT_IS_IRLUNIT_VALID(dev,irlUnit))
    {
        DBG_INFO(("GT_BAD_PARAM\n"));
        return GT_BAD_PARAM;
    }

    /* get port list that share ingress resource */
    retVal = pirlGetPortVec(dev, irlUnit, portVec);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Getting Port State failed\n"));
        return retVal;
    }

    /* check if the given portVec is valid */
    if (!*portVec)
    {
        DBG_INFO(("IRL Unit not Activated\n"));
        return GT_FAIL;
    }

    DBG_INFO(("OK.\n"));
    return GT_OK;

}



/*******************************************************************************
* grcGetPirlFcMode
*
* DESCRIPTION:
*       This routine gets Port Ingress Rate Limit Flow Control mode.
*        When EBSLimitAction is programmed to generate a flow control message,
*        the deassertion of flow control is controlled by this mode.
*            GT_PIRL_FC_DEASSERT_EMPTY:
*                De-assert when the ingress rate resource has become empty
*            GT_PIRL_FC_DEASSERT_CBS_LIMIT
*                De-assert when the ingress rate resource has enough room as
*                specified by the CBSLimit.
*        Please refer to GT_PIRL_RESOURCE structure for EBSLimitAction and
*        CBSLimit.
*
* INPUTS:
*       port - logical port number
*
* OUTPUTS:
*        mode - GT_PIRL_FC_DEASSERT enum type
*
* RETURNS:
*       GT_OK               - on success
*       GT_FAIL             - on error
*        GT_NOT_SUPPORTED    - if current device does not support this feature.
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS grcGetPirlFcMode
(
    IN  GT_QD_DEV    *dev,
    IN  GT_LPORT    port,
    OUT GT_PIRL_FC_DEASSERT        *mode
)
{
    GT_U16          data;
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U8           hwPort;        /* Physical port.               */

    DBG_INFO(("grcSetDaNrlEn Called.\n"));

    hwPort = GT_LPORT_2_PORT(port);

    /* check if the given Switch supports this feature. */
    if (!IS_IN_DEV_GROUP(dev,DEV_PIRL_RESOURCE))
    {
           DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* Get the PirlFcMode.            */
    retVal = hwGetPortRegField(dev,hwPort, QD_REG_INGRESS_RATE_CTRL,12,1,&data);
    if(retVal != GT_OK)
       {
        DBG_INFO(("Failed.\n"));
           return retVal;
    }

    *mode = (GT_PIRL_FC_DEASSERT)data;
    DBG_INFO(("OK.\n"));

    return GT_OK;
}

/*******************************************************************************
* gpirlGetIngressRateResource
*
* DESCRIPTION:
*       This routine gets Ingress Rate Limiting Resources assigned to the port.
*        This vector is used to attach specific counter resources to the physical
*        port. And the same counter resource can be attached to more than one port.
*
* INPUTS:
*       port   - logical port number
*
* OUTPUTS:
*        resVec - resource vector (bit 11:0, since there is 12 resources)
*
* RETURNS:
*       GT_OK               - on success
*       GT_FAIL             - on error
*        GT_NOT_SUPPORTED    - if current device does not support this feature.
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gpirlGetIngressRateResource
(
    IN  GT_QD_DEV    *dev,
    IN  GT_LPORT    port,
    OUT GT_U32        *resVec
)
{
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U8           hwPort;        /* Physical port.               */
    GT_U16            data;

    DBG_INFO(("grcGetIngressRateResource Called.\n"));

    hwPort = GT_LPORT_2_PORT(port);

    /* check if the given Switch supports this feature. */
    if (!IS_IN_DEV_GROUP(dev,DEV_PIRL_RESOURCE))
    {
           DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    /* Get the resource vector.            */
    retVal = hwGetPortRegField(dev,hwPort, QD_REG_INGRESS_RATE_CTRL,0,12,&data);
    if(retVal != GT_OK)
       {
        DBG_INFO(("Failed.\n"));
           return retVal;
    }

    *resVec = (GT_U32)data;

    DBG_INFO(("OK.\n"));

    return GT_OK;
}

/*******************************************************************************
* gpirlSetCurTimeUpInt
*
* DESCRIPTION:
*       This function sets the current time update interval.
*        Please contact FAE for detailed information.
*
* INPUTS:
*       upInt - updata interval (0 ~ 7)
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK      - on success
*       GT_FAIL    - on error
*        GT_BAD_PARAM - if invalid parameter is given
*       GT_NOT_SUPPORTED - if current device does not support this feature.
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS gpirlSetCurTimeUpInt
(
    IN  GT_QD_DEV              *dev,
    IN    GT_U32                upInt
)
{
    GT_STATUS       retVal;        /* Functions return value */
    GT_PIRL_OPERATION    op;
    GT_PIRL_OP_DATA        opData;

    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_PIRL_RESOURCE))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    if (upInt > 0x7)
        return GT_BAD_PARAM;

    op = PIRL_READ_RESOURCE;

    opData.irlUnit = 0xF;
    opData.irlReg = 1;
    opData.irlData = 0;

    retVal = pirlOperationPerform(dev, op, &opData);
    if (retVal != GT_OK)
    {
           DBG_INFO(("PIRL OP Failed.\n"));
           return retVal;
    }

    op = PIRL_WRITE_RESOURCE;
    opData.irlData = (opData.irlData & 0xFFF8) | (GT_U16)upInt;

    retVal = pirlOperationPerform(dev, op, &opData);
    if (retVal != GT_OK)
    {
           DBG_INFO(("PIRL OP Failed.\n"));
           return retVal;
    }

    return GT_OK;
}

/****************************************************************************/
/* Internal functions.                                                  */
/****************************************************************************/

/*******************************************************************************
* gpirlInitialize
*
* DESCRIPTION:
*       This routine initializes PIRL Resources.
*
* INPUTS:
*       None
*
* OUTPUTS:
*       None
*
* RETURNS:
*       None
*
* COMMENTS:
*       None
*
*******************************************************************************/
GT_STATUS gpirlInitialize
(
    IN  GT_QD_DEV              *dev
)
{
    GT_STATUS           retVal;
    GT_LPORT        port;
    GT_U8           hwPort;        /* Physical port.               */

    /* reset port's ingress resource bit */
    for(port=0; port<dev->numOfPorts; port++)
    {
        hwPort = GT_LPORT_2_PORT(port);

        /* Set the resource vector.            */
        retVal = hwSetPortRegField(dev,hwPort, QD_REG_INGRESS_RATE_CTRL,0,12,0);
        if(retVal != GT_OK)
           {
            DBG_INFO(("Failed.\n"));
               return retVal;
        }
    }

    retVal = pirlInitialize(dev);
    if(retVal != GT_OK)
    {
        DBG_INFO(("Failed.\n"));
        return retVal;
    }

    return GT_OK;
}


/*******************************************************************************
* statsOperationPerform
*
* DESCRIPTION:
*       This function accesses Ingress Rate Command Register and Data Register.
*
* INPUTS:
*       pirlOp       - The stats operation bits to be written into the stats
*                     operation register.
*       port        - port number
*       counter     - counter to be read if it's read operation
*
* OUTPUTS:
*       pirlData   - points to the data storage where the MIB counter will be saved.
*
* RETURNS:
*       GT_OK on success,
*       GT_FAIL otherwise.
*
* COMMENTS:
*
*******************************************************************************/
static GT_STATUS pirlOperationPerform
(
    IN    GT_QD_DEV           *dev,
    IN    GT_PIRL_OPERATION   pirlOp,
    INOUT GT_PIRL_OP_DATA     *opData
)
{
    GT_STATUS       retVal;    /* Functions return value */
    GT_U16          data;     /* temporary Data storage */

    gtSemTake(dev,dev->pirlRegsSem,OS_WAIT_FOREVER);

    /* Wait until the pirl in ready. */
#ifdef GT_RMGMT_ACCESS
    {
      HW_DEV_REG_ACCESS regAccess;

      regAccess.entries = 1;

      regAccess.rw_reg_list[0].cmd = HW_REG_WAIT_TILL_0;
      regAccess.rw_reg_list[0].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
      regAccess.rw_reg_list[0].reg = QD_REG_INGRESS_RATE_COMMAND;
      regAccess.rw_reg_list[0].data = 15;
      retVal = hwAccessMultiRegs(dev, &regAccess);
      if(retVal != GT_OK)
      {
        gtSemGive(dev,dev->pirlRegsSem);
        return retVal;
      }
    }
#else
    data = 1;
    while(data == 1)
    {
        retVal = hwGetGlobal2RegField(dev,QD_REG_INGRESS_RATE_COMMAND,15,1,&data);
        if(retVal != GT_OK)
        {
            gtSemGive(dev,dev->pirlRegsSem);
            return retVal;
        }
    }
#endif

    /* Set the PIRL Operation register */
    switch (pirlOp)
    {
        case PIRL_INIT_ALL_RESOURCE:
            data = (1 << 15) | (PIRL_INIT_ALL_RESOURCE << 12);
            retVal = hwWriteGlobal2Reg(dev,QD_REG_INGRESS_RATE_COMMAND,data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->pirlRegsSem);
                return retVal;
            }
            break;
        case PIRL_INIT_RESOURCE:
            data = (GT_U16)((1 << 15) | (PIRL_INIT_RESOURCE << 12) |
                    ((opData->irlUnit&0xF)<< 4));
            retVal = hwWriteGlobal2Reg(dev,QD_REG_INGRESS_RATE_COMMAND,data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->pirlRegsSem);
                return retVal;
            }
            break;

        case PIRL_WRITE_RESOURCE:
            data = (GT_U16)opData->irlData;
            retVal = hwWriteGlobal2Reg(dev,QD_REG_INGRESS_RATE_DATA,data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->pirlRegsSem);
                return retVal;
            }

            data = (GT_U16)((1 << 15) | (PIRL_WRITE_RESOURCE << 12) |
                    ((opData->irlUnit&0xF) << 4) | (opData->irlReg & 0xF));
            retVal = hwWriteGlobal2Reg(dev,QD_REG_INGRESS_RATE_COMMAND,data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->pirlRegsSem);
                return retVal;
            }
            break;

        case PIRL_READ_RESOURCE:
            data = (GT_U16)((1 << 15) | (PIRL_READ_RESOURCE << 12) |
                    ((opData->irlUnit&0xF) << 4) | (opData->irlReg & 0xF));
            retVal = hwWriteGlobal2Reg(dev,QD_REG_INGRESS_RATE_COMMAND,data);
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->pirlRegsSem);
                return retVal;
            }

#ifdef GT_RMGMT_ACCESS
            {
              HW_DEV_REG_ACCESS regAccess;

              regAccess.entries = 1;

              regAccess.rw_reg_list[0].cmd = HW_REG_WAIT_TILL_0;
              regAccess.rw_reg_list[0].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
              regAccess.rw_reg_list[0].reg = QD_REG_INGRESS_RATE_COMMAND;
              regAccess.rw_reg_list[0].data = 15;
              retVal = hwAccessMultiRegs(dev, &regAccess);
              if(retVal != GT_OK)
              {
                gtSemGive(dev,dev->pirlRegsSem);
                return retVal;
              }
            }
#else
            data = 1;
            while(data == 1)
            {
                retVal = hwGetGlobal2RegField(dev,QD_REG_INGRESS_RATE_COMMAND,15,1,&data);
                if(retVal != GT_OK)
                {
                    gtSemGive(dev,dev->pirlRegsSem);
                    return retVal;
                }
            }
#endif

            retVal = hwReadGlobal2Reg(dev,QD_REG_INGRESS_RATE_DATA,&data);
            opData->irlData = (GT_U32)data;
            if(retVal != GT_OK)
            {
                gtSemGive(dev,dev->pirlRegsSem);
                return retVal;
            }
            gtSemGive(dev,dev->pirlRegsSem);
            return retVal;

        default:

            gtSemGive(dev,dev->pirlRegsSem);
            return GT_FAIL;
    }

    /* Wait until the pirl in ready. */
#ifdef GT_RMGMT_ACCESS
    {
      HW_DEV_REG_ACCESS regAccess;

      regAccess.entries = 1;

      regAccess.rw_reg_list[0].cmd = HW_REG_WAIT_TILL_0;
      regAccess.rw_reg_list[0].addr = CALC_SMI_DEV_ADDR(dev, 0, GLOBAL2_REG_ACCESS);
      regAccess.rw_reg_list[0].reg = QD_REG_INGRESS_RATE_COMMAND;
      regAccess.rw_reg_list[0].data = 15;
      retVal = hwAccessMultiRegs(dev, &regAccess);
      if(retVal != GT_OK)
      {
        gtSemGive(dev,dev->pirlRegsSem);
        return retVal;
      }
    }
#else
    data = 1;
    while(data == 1)
    {
        retVal = hwGetGlobal2RegField(dev,QD_REG_INGRESS_RATE_COMMAND,15,1,&data);
        if(retVal != GT_OK)
        {
            gtSemGive(dev,dev->pirlRegsSem);
            return retVal;
        }
    }
#endif

    gtSemGive(dev,dev->pirlRegsSem);
    return retVal;
}

/*
 * Initialize all PIRL resources to the inital state.
*/
static GT_STATUS pirlInitialize
(
    IN  GT_QD_DEV              *dev
)
{
    GT_STATUS       retVal;    /* Functions return value */
    GT_PIRL_OPERATION    op;

    op = PIRL_INIT_ALL_RESOURCE;

    retVal = pirlOperationPerform(dev, op, NULL);
    if (retVal != GT_OK)
    {
           DBG_INFO(("PIRL OP Failed.\n"));
           return retVal;
    }

    retVal = gpirlSetCurTimeUpInt(dev,7);
    if (retVal != GT_OK)
    {
           DBG_INFO(("PIRL OP Failed.\n"));
    }

    return retVal;
}

/*
 * Initialize the selected PIRL resource to the inital state.
 * This function initializes only the BSM structure for the IRL Unit.
*/
static GT_STATUS pirlInitIRLUnit
(
    IN  GT_QD_DEV              *dev,
    IN    GT_U32                irlUnit
)
{
    GT_STATUS       retVal;    /* Functions return value */
    GT_PIRL_OPERATION    op;
    GT_PIRL_OP_DATA        opData;

    op = PIRL_INIT_RESOURCE;
    opData.irlUnit = irlUnit;

    retVal = pirlOperationPerform(dev, op, &opData);
    if (retVal != GT_OK)
    {
           DBG_INFO(("PIRL OP Failed.\n"));
           return retVal;
    }

    return retVal;
}

/*
 * convert PIRL Data structure to PIRL Resource structure.
 * if PIRL Data is not valid, return GT_BAD_PARARM;
*/
static GT_STATUS pirlDataToResource
(
    IN  GT_QD_DEV              *dev,
    IN  GT_PIRL_DATA        *pirlData,
    OUT GT_PIRL_RESOURCE    *res
)
{
    GT_U16 typeMask;

    switch(pirlData->accountQConf)
    {
        case GT_FALSE:
        case GT_TRUE:
            res->accountQConf = pirlData->accountQConf;
            break;
        default:
            return GT_BAD_PARAM;
    }

    switch(pirlData->accountFiltered)
    {
        case GT_FALSE:
        case GT_TRUE:
            res->accountFiltered = pirlData->accountFiltered;
            break;
        default:
            return GT_BAD_PARAM;
    }

    switch(pirlData->ebsLimitAction)
    {
        case ESB_LIMIT_ACTION_DROP:
        case ESB_LIMIT_ACTION_FC:
            res->ebsLimitAction = pirlData->ebsLimitAction;
            break;
        default:
            return GT_BAD_PARAM;
    }

    if(pirlData->customSetup.isValid == GT_TRUE)
    {
        res->ebsLimit = pirlData->customSetup.ebsLimit;
        res->cbsLimit = pirlData->customSetup.cbsLimit;
        res->bktIncrement = pirlData->customSetup.bktIncrement;
        res->bktRateFactor = pirlData->customSetup.bktRateFactor;
    }
    else
    {
        if(pirlData->ingressRate == 0)
            return GT_BAD_PARAM;

        if(pirlData->ingressRate < 1000)    /* less than 1Mbps */
        {
            /* it should be divided by 64 */
            if(pirlData->ingressRate % 64)
                return GT_BAD_PARAM;
            res->bktRateFactor = pirlData->ingressRate/64;
        }
        else if(pirlData->ingressRate <= 100000)    /* less than or equal to 100Mbps */
        {
            /* it should be divided by 1000 */
            if(pirlData->ingressRate % 1000)
                return GT_BAD_PARAM;
            res->bktRateFactor = pirlData->ingressRate/64 + ((pirlData->ingressRate % 64)?1:0);
        }
        else if(pirlData->ingressRate <= 200000)    /* less than or equal to 200Mbps */
        {
            /* it should be divided by 10000 */
            if(pirlData->ingressRate % 10000)
                return GT_BAD_PARAM;
            res->bktRateFactor = pirlData->ingressRate/64 + ((pirlData->ingressRate % 64)?1:0);
        }
        else
            return GT_BAD_PARAM;

        res->ebsLimit = RECOMMENDED_ESB_LIMIT(dev, pirlData->ingressRate);
        res->cbsLimit = RECOMMENDED_CBS_LIMIT(dev, pirlData->ingressRate);
        res->bktIncrement = RECOMMENDED_BUCKET_INCREMENT(dev, pirlData->ingressRate);
    }

    switch(pirlData->bktRateType)
    {
        case BUCKET_TYPE_TRAFFIC_BASED:
            res->bktRateType = pirlData->bktRateType;

            if (IS_IN_DEV_GROUP(dev,DEV_RESTRICTED_PIRL_RESOURCE))
            {
                typeMask = 0xF;
            }
            else
            {
                typeMask = 0x7F;
            }

            if (pirlData->bktTypeMask > typeMask)
            {
                return GT_BAD_PARAM;
            }
            else
            {
                res->bktTypeMask = pirlData->bktTypeMask;
            }

            break;

        case BUCKET_TYPE_RATE_BASED:
            if (IS_IN_DEV_GROUP(dev,DEV_RESTRICTED_PIRL_RESOURCE))
                return GT_BAD_PARAM;
            res->bktRateType = pirlData->bktRateType;
            res->bktTypeMask = 0;
            break;

        default:
            return GT_BAD_PARAM;
    }

    switch(pirlData->byteTobeCounted)
    {
        case GT_PIRL_COUNT_ALL_LAYER1:
            res->byteTobeCounted = 1;
            break;
        case GT_PIRL_COUNT_ALL_LAYER2:
            res->byteTobeCounted = 2;
            break;
        case GT_PIRL_COUNT_ALL_LAYER3:
            res->byteTobeCounted = 6;
            break;
        default:
            return GT_BAD_PARAM;
    }

    return GT_OK;
}

/*
 * convert PIRL Resource structure to PIRL Data structure.
*/
static GT_STATUS pirlResourceToData
(
    IN  GT_QD_DEV              *dev,
    IN  GT_PIRL_RESOURCE    *res,
    OUT GT_PIRL_DATA        *pirlData
)
{
    GT_U32    rate;
    GT_U32    factor;

    pirlData->accountQConf = res->accountQConf;
    pirlData->accountFiltered = res->accountFiltered;
    pirlData->ebsLimitAction = res->ebsLimitAction;

    pirlData->customSetup.isValid = GT_FALSE;

    FACTOR_FROM_BUCKET_INCREMENT(dev,res->bktIncrement,factor);

    rate = res->bktRateFactor * factor;
    if(rate == 0)
    {
        pirlData->ingressRate = 0;
        pirlData->customSetup.isValid = GT_TRUE;
        pirlData->customSetup.ebsLimit = res->ebsLimit;
        pirlData->customSetup.cbsLimit = res->cbsLimit;
        pirlData->customSetup.bktIncrement = res->bktIncrement;
        pirlData->customSetup.bktRateFactor = res->bktRateFactor;
    }
    else if(rate < 1000)
    {
        pirlData->ingressRate = rate;
    }
    else if(rate < 100000)
    {
        pirlData->ingressRate = rate - (rate % 1000);
    }
    else
    {
        pirlData->ingressRate = rate - (rate % 10000);
    }

    pirlData->bktRateType = res->bktRateType;
    pirlData->bktTypeMask = res->bktTypeMask;

    switch(res->byteTobeCounted)
    {
        case 1:
            pirlData->byteTobeCounted = GT_PIRL_COUNT_ALL_LAYER1;
            break;
        case 2:
            pirlData->byteTobeCounted = GT_PIRL_COUNT_ALL_LAYER2;
            break;
        case 6:
            pirlData->byteTobeCounted = GT_PIRL_COUNT_ALL_LAYER3;
            break;
        default:
            return GT_BAD_PARAM;
    }

    return GT_OK;
}

/*******************************************************************************
* pirlWriteResource
*
* DESCRIPTION:
*       This function writes IRL Resource to BCM (Bucket Configuration Memory)
*
* INPUTS:
*        irlUnit - resource unit to be accessed
*       res     - IRL Resource data
*
* OUTPUTS:
*       Nont.
*
* RETURNS:
*       GT_OK on success,
*       GT_FAIL otherwise.
*
* COMMENTS:
*
*******************************************************************************/
static GT_STATUS pirlWriteResource
(
    IN  GT_QD_DEV              *dev,
    IN    GT_U32                irlUnit,
    IN  GT_PIRL_RESOURCE    *res
)
{
    GT_STATUS       retVal;            /* Functions return value */
    GT_U16          data[8];     /* temporary Data storage */
    GT_PIRL_OPERATION    op;
    GT_PIRL_OP_DATA        opData;
    int                i;

    op = PIRL_WRITE_RESOURCE;

    /* reg0 data */
    data[0] = (GT_U16)((res->bktRateType << 15) |    /* Bit[15] : Bucket Rate Type */
                      (res->bktTypeMask << 4 ) |        /* Bit[14:4] : Traffic Type   */
                      res->byteTobeCounted );            /* Bit[3:0] : Bytes to be counted */

    /* reg1 data */
    data[1] = (GT_U16)res->bktIncrement;    /* Bit[11:0] : Bucket Increment */

    /* reg2 data */
    data[2] = (GT_U16)res->bktRateFactor;    /* Bit[15:0] : Bucket Rate Factor */

    /* reg3 data */
    data[3] = (GT_U16)(res->cbsLimit & 0xFFF) << 4;    /* Bit[15:4] : CBS Limit[11:0] */

    /* reg4 data */
    data[4] = (GT_U16)(res->cbsLimit >> 12);        /* Bit[11:0] : CBS Limit[23:12] */

    /* reg5 data */
    data[5] = (GT_U16)(res->ebsLimit & 0xFFFF);        /* Bit[15:0] : EBS Limit[15:0] */

    /* reg6 data */
    data[6] = (GT_U16)((res->ebsLimit >> 16)    |    /* Bit[7:0] : EBS Limit[23:16] */
                    (res->ebsLimitAction << 12)    |    /* Bit[12] : EBS Limit Action */
                    (res->accountFiltered << 14)|    /* Bit[14] : Account Filtered */
                    (res->accountQConf << 15));        /* Bit[15] : Account QConf */
    /* reg7 data */
    data[7] = 0;    /* Reserved */

    for(i=0; i<8; i++)
    {
        opData.irlUnit = irlUnit;
        opData.irlReg = i;
        opData.irlData = data[i];

        retVal = pirlOperationPerform(dev, op, &opData);
        if (retVal != GT_OK)
        {
            DBG_INFO(("PIRL OP Failed.\n"));
            return retVal;
        }
    }

    return GT_OK;
}


/*******************************************************************************
* pirlReadResource
*
* DESCRIPTION:
*       This function reads IRL Resource from BCM (Bucket Configuration Memory)
*
* INPUTS:
*        irlUnit - resource unit to be accessed
*
* OUTPUTS:
*       res - IRL Resource data
*
* RETURNS:
*       GT_OK on success,
*       GT_FAIL otherwise.
*
* COMMENTS:
*
*******************************************************************************/
static GT_STATUS pirlReadResource
(
    IN  GT_QD_DEV              *dev,
    IN    GT_U32                irlUnit,
    OUT GT_PIRL_RESOURCE    *res
)
{
    GT_STATUS       retVal;            /* Functions return value */
    GT_U16          data[8];     /* temporary Data storage */
    GT_PIRL_OPERATION    op;
    GT_PIRL_OP_DATA        opData;
    int                i;

    op = PIRL_READ_RESOURCE;

    for(i=0; i<8; i++)
    {
        opData.irlUnit = irlUnit;
        opData.irlReg = i;
        opData.irlData = 0;

        retVal = pirlOperationPerform(dev, op, &opData);
        if (retVal != GT_OK)
        {
            DBG_INFO(("PIRL OP Failed.\n"));
            return retVal;
        }

        data[i] = (GT_U16)opData.irlData;
    }


    /* reg0 data */
    res->bktRateType = (data[0] >> 15) & 0x1;
    res->bktTypeMask = (data[0] >> 4) & 0x7F;

    res->byteTobeCounted = data[0] & 0xF;

    /* reg1 data */
    res->bktIncrement = data[1] & 0xFFF;

    /* reg2 data */
    res->bktRateFactor = data[2] & 0xFFFF;

    /* reg3,4 data */
    res->cbsLimit = ((data[3] >> 4) & 0xFFF) | ((data[4] & 0xFFF) << 12);

    /* reg5,6 data */
    res->ebsLimit = data[5] | ((data[6] & 0xFF) << 16);

    /* reg6 data */
    res->ebsLimitAction = (data[6] >> 12) & 0x1;
    res->accountFiltered = (data[6] >> 14) & 0x1;
    res->accountQConf = (data[6] >> 15) & 0x1;

    return GT_OK;
}

/*******************************************************************************
* pirlSetPortVec
*
* DESCRIPTION:
*       This routine sets port list that share the bucket and resets ports that
*        do not share the bucket.
*
* INPUTS:
*        irlUnit  - bucket to be used.
*       portVec  - the list of ports that share the bucket.
*
* OUTPUTS:
*       None.
*
* RETURNS:
*       GT_OK               - on success
*       GT_FAIL             - on error
*
* COMMENTS:
*
*******************************************************************************/
static GT_STATUS pirlSetPortVec
(
    IN  GT_QD_DEV    *dev,
    IN  GT_U32        irlUnit,
    IN  GT_U32        portVec
)
{
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_LPORT        port;
    GT_U8           hwPort;        /* Physical port.               */
    GT_U16            data;

    for(port=0; port<dev->numOfPorts; port++)
    {
        if(GT_IS_PORT_SET(portVec,port))
            data = 1;
        else
            data = 0;

        hwPort = GT_LPORT_2_PORT(port);

        /* Set the resource vector.            */
        retVal = hwSetPortRegField(dev,hwPort, QD_REG_INGRESS_RATE_CTRL,(GT_U8)irlUnit,1,data);
        if(retVal != GT_OK)
           {
            DBG_INFO(("Failed.\n"));
               return retVal;
        }
    }

    DBG_INFO(("OK.\n"));

    return GT_OK;
}


/*******************************************************************************
* pirlGetPortVec
*
* DESCRIPTION:
*       This routine gets port list that share the bucket.
*
* INPUTS:
*        irlUnit  - bucket to be used.
*
* OUTPUTS:
*       portVec  - the list of ports that share the bucket.
*
* RETURNS:
*       GT_OK               - on success
*       GT_FAIL             - on error
*
* COMMENTS:
*
*******************************************************************************/
static GT_STATUS pirlGetPortVec
(
    IN  GT_QD_DEV    *dev,
    IN  GT_U32        irlUnit,
    OUT GT_U32        *portVec
)
{
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_LPORT        port;
    GT_U8           hwPort;        /* Physical port.               */
    GT_U16            data;

    *portVec = 0;

    for(port=0; port<dev->numOfPorts; port++)
    {
        hwPort = GT_LPORT_2_PORT(port);

        /* Set the resource vector.            */
        retVal = hwGetPortRegField(dev,hwPort, QD_REG_INGRESS_RATE_CTRL,(GT_U8)irlUnit,1,&data);
        if(retVal != GT_OK)
           {
            DBG_INFO(("Failed.\n"));
               return retVal;
        }

        if(data == 1)
            *portVec |= (1 << port);
    }

    DBG_INFO(("OK.\n"));

    return GT_OK;
}


/*******************************************************************************
* pirlSetFcMode
*
* DESCRIPTION:
*       This routine gets Port Ingress Rate Limit Flow Control mode.
*        When EBSLimitAction is programmed to generate a flow control message,
*        the deassertion of flow control is controlled by this mode.
*            GT_PIRL_FC_DEASSERT_EMPTY:
*                De-assert when the ingress rate resource has become empty
*            GT_PIRL_FC_DEASSERT_CBS_LIMIT
*                De-assert when the ingress rate resource has enough room as
*                specified by the CBSLimit.
*        Please refer to GT_PIRL_RESOURCE structure for EBSLimitAction and
*        CBSLimit.
*
* INPUTS:
*       port - logical port number
*        mode - GT_PIRL_FC_DEASSERT enum type
*
* OUTPUTS:
*        None.
*
* RETURNS:
*       GT_OK               - on success
*       GT_FAIL             - on error
*        GT_NOT_SUPPORTED    - if current device does not support this feature.
*
* COMMENTS:
*
*******************************************************************************/
static GT_STATUS pirlSetFcMode
(
    IN  GT_QD_DEV    *dev,
    IN  GT_LPORT    port,
    IN  GT_PIRL_FC_DEASSERT        mode
)
{
    GT_U16          data;
    GT_STATUS       retVal;         /* Functions return value.      */
    GT_U8           hwPort;        /* Physical port.               */

    DBG_INFO(("pirlSetFcMode Called.\n"));

    hwPort = GT_LPORT_2_PORT(port);

    data = (GT_U16) mode;

    /* Set the PirlFcMode.            */
    retVal = hwSetPortRegField(dev,hwPort, QD_REG_INGRESS_RATE_CTRL,12,1,data);
    if(retVal != GT_OK)
       {
        DBG_INFO(("Failed.\n"));
           return retVal;
    }

    DBG_INFO(("OK.\n"));

    return GT_OK;
}

#define PIRL_DEBUG
#ifdef PIRL_DEBUG
/*******************************************************************************
* pirlDumpResource
*
* DESCRIPTION:
*       This function dumps IRL Resource register values.
*
* INPUTS:
*        irlUnit  - resource unit to be accessed
*        dataLen  - data size.
*
* OUTPUTS:
*       data - IRL Resource data
*
* RETURNS:
*       GT_OK on success,
*       GT_FAIL otherwise.
*
* COMMENTS:
*
*******************************************************************************/
GT_STATUS pirlDumpResource
(
    IN  GT_QD_DEV              *dev,
    IN    GT_U32                irlUnit,
    IN    GT_U32                dataLen,
    OUT GT_U16                *data
)
{
    GT_STATUS       retVal;        /* Functions return value */
    GT_PIRL_OPERATION    op;
    GT_PIRL_OP_DATA        opData;
    GT_U32                i;

    /* check if device supports this feature */
    if (!IS_IN_DEV_GROUP(dev,DEV_PIRL_RESOURCE))
    {
        DBG_INFO(("GT_NOT_SUPPORTED\n"));
        return GT_NOT_SUPPORTED;
    }

    op = PIRL_READ_RESOURCE;

    for(i=0; i<dataLen; i++)
    {
        opData.irlUnit = irlUnit;
        opData.irlReg = i;
        opData.irlData = 0;

        retVal = pirlOperationPerform(dev, op, &opData);
        if (retVal != GT_OK)
        {
            DBG_INFO(("PIRL OP Failed.\n"));
            return retVal;
        }

        data[i] = (GT_U16)opData.irlData;
    }

    return GT_OK;
}
#endif /* PIRL_DEBUG */
